//
//  WCFileBrowserOutlineView.m
//  WabbitCode
//
//  Created by William Towe on 3/26/09.
//  Copyright 2009 Revolution Software. All rights reserved.
//

#import "WCFileBrowserOutlineView.h"
#import "WCIconAndTextFieldCell.h"
#import "WCGradientTableHeaderCell.h"


@interface WCFileBrowserFile : NSTreeNode {
	WCFileBrowserOutlineView *_fileBrowserOutlineView;
	NSString *_fileName;
}
@property (readonly) WCFileBrowserOutlineView *fileBrowserOutlineView;
@property (readonly) NSString *fileName;
@property (readonly) NSString *filePath;
@property (readonly) NSString *directoryPath;
@property (readonly) BOOL isDirectory;

+ (WCFileBrowserFile *)fileBrowserFileWithFileName:(NSString *)fileName fileBrowser:(WCFileBrowserOutlineView *)fileBrowser;
@end

@implementation WCFileBrowserFile
- (void)dealloc {
	[_fileName release];
	[super dealloc];
}

@synthesize fileName=_fileName,fileBrowserOutlineView=_fileBrowserOutlineView;

@dynamic filePath;
- (NSString *)filePath {
	if ([self parentNode] == nil)
		return [[[self fileBrowserOutlineView] rootFolderPath] stringByAppendingPathComponent:[self fileName]];
	return [[(WCFileBrowserFile *)[self parentNode] filePath] stringByAppendingPathComponent:[self fileName]];
}

@dynamic directoryPath;
- (NSString *)directoryPath {
	return [[self filePath] stringByDeletingLastPathComponent];
}

@dynamic isDirectory;
- (BOOL)isDirectory {
	BOOL flag;
	if ([[NSFileManager defaultManager] fileExistsAtPath:[self filePath] isDirectory:&flag] &&
		flag &&
		![[NSWorkspace sharedWorkspace] isFilePackageAtPath:[self filePath]])
		return YES;
	return NO;
}

- (id)initWithFileName:(NSString *)fileName fileBrowser:(WCFileBrowserOutlineView *)fileBrowser; {
	if (!(self = [super init]))
		return nil;
	
	_fileBrowserOutlineView = fileBrowser;
	_fileName = [fileName copy];
	
	return self;
}

+ (WCFileBrowserFile *)fileBrowserFileWithFileName:(NSString *)fileName fileBrowser:(WCFileBrowserOutlineView *)fileBrowser; {
	return [[[[self class] alloc] initWithFileName:fileName fileBrowser:fileBrowser] autorelease];
}
@end

static void fsevents_callback(ConstFSEventStreamRef streamRef, void *userData, size_t numEvents, void *eventPaths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]) {
	[(WCFileBrowserOutlineView *)userData reloadData];
}

@implementation WCFileBrowserOutlineView
#pragma mark *** Subclass Overrides ***
- (id)initWithCoder:(NSCoder *)coder {
	if (!(self = [super initWithCoder:coder]))
		return nil;
	
	/*
	NSTableColumn *oColumn = [[self tableColumns] objectAtIndex:0];
	[oColumn setIdentifier:NSLocalizedString(@"File Browser",@"File Browser")];
	WCGradientTableHeaderCell *hCell = [[[WCGradientTableHeaderCell alloc] initTextCell:[oColumn identifier]] autorelease];
	[oColumn setHeaderCell:hCell];
	 */

	[self setFocusRingType:NSFocusRingTypeNone];
	[self setSelectionHighlightStyle:NSTableViewSelectionHighlightStyleSourceList];
	[self setAllowsColumnSelection:NO];
	[self setAllowsColumnReordering:NO];
	[self setAllowsEmptySelection:YES];
	[self setAllowsMultipleSelection:NO];
	[self setAllowsTypeSelect:YES];
	[self setAllowsColumnResizing:NO];
	[self setDataSource:self];
	[self setDelegate:self];
	
	[self setDoubleAction:@selector(fileBrowserOutlineViewDoubleAction:)];
	[self setTarget:self];
	
	return self;
}

- (void)dealloc {
	if (_fsEventStream != NULL) {
		FSEventStreamStop(_fsEventStream);
		FSEventStreamInvalidate(_fsEventStream);
		FSEventStreamRelease(_fsEventStream);
	}
	
	[_rootFilesAndFolders release];
	[_rootFolderPath release];
	[super dealloc];
}

- (void)awakeFromNib {
	[[self enclosingScrollView] setHasHorizontalScroller:NO];
}
#pragma mark NSOutlineViewDatasource Protocol
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
	if (!item)
		return [[self rootFilesAndFolders] objectAtIndex:index];
	return [[item childNodes] objectAtIndex:index];
}

- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
	return [item isDirectory];
}

- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
	NSArray *currentFileNames = nil;
	NSMutableArray *currentFileBrowserFiles = nil;
	NSMutableArray *fileBrowserFilesToRemove = [NSMutableArray array];
	NSString *filePath = nil;
	NSUInteger insertIndex = 0;
	
	if (!item) {
		currentFileNames = [[NSFileManager defaultManager] directoryContentsAtPath:[self rootFolderPath]];
		currentFileBrowserFiles = [self rootFilesAndFolders];
		filePath = [self rootFolderPath];
	}
	else {
		currentFileNames = [[NSFileManager defaultManager] directoryContentsAtPath:[item filePath]];
		currentFileBrowserFiles = [item mutableChildNodes];
		filePath = [item filePath];
	}
	
	for (WCFileBrowserFile *file in currentFileBrowserFiles) {
		if (![currentFileNames containsObject:[file fileName]])
			[fileBrowserFilesToRemove addObject:file];
	}
	
	[currentFileBrowserFiles removeObjectsInArray:fileBrowserFilesToRemove];
	
	NSArray *browserFileNames = [currentFileBrowserFiles valueForKey:@"fileName"];
	BOOL isDirectory = NO;
	for (NSString *fileName in currentFileNames) {
		if ([fileName hasPrefix:@"."])
			continue;
		
		if (_onlyShowFolders && [[NSFileManager defaultManager] fileExistsAtPath:[filePath stringByAppendingPathComponent:fileName] isDirectory:&isDirectory] && (!isDirectory || [[NSWorkspace sharedWorkspace] isFilePackageAtPath:[filePath stringByAppendingPathComponent:fileName]]))
			continue;
		
		if (![browserFileNames containsObject:fileName])
			[currentFileBrowserFiles insertObject:[WCFileBrowserFile fileBrowserFileWithFileName:fileName fileBrowser:self] atIndex:insertIndex];
		
		insertIndex++;
	}
	
	return [currentFileBrowserFiles count];
}

- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
	return [item fileName];
}
#pragma mark NSOutlineView Delegate
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item {	
	[cell setIcon:[[NSWorkspace sharedWorkspace] iconForFile:[item filePath]]];
	
	static NSSize smallIconSize = {16.0, 16.0};
	[cell setIconSize:smallIconSize];
}
#pragma mark *** Public Methods ***
@synthesize rootFilesAndFolders=_rootFilesAndFolders,rootFolderPath=_rootFolderPath,onlyShowFolders=_onlyShowFolders;

- (void)setRootFolderPath:(NSString *)value {
	if (_rootFolderPath == value)
		return;
	
	[_rootFolderPath release];
	_rootFolderPath = [value copy];
	
	if (_fsEventStream != NULL) {
		FSEventStreamStop(_fsEventStream);
		FSEventStreamInvalidate(_fsEventStream);
		FSEventStreamRelease(_fsEventStream);
	}
	
	FSEventStreamContext context = {0, (void *)self, NULL, NULL, NULL};
	
	_fsEventStream = FSEventStreamCreate(NULL, &fsevents_callback, &context, (CFArrayRef)[NSArray arrayWithObject:NSHomeDirectory()], kFSEventStreamEventIdSinceNow, (CFTimeInterval)0.2, kFSEventStreamCreateFlagUseCFTypes);
	
	FSEventStreamScheduleWithRunLoop(_fsEventStream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
	FSEventStreamStart(_fsEventStream);
	
	[self reloadData];
}

- (NSMutableArray *)rootFilesAndFolders {
	if (!_rootFilesAndFolders) {
		_rootFilesAndFolders = [[NSMutableArray alloc] init];
	}
	return _rootFilesAndFolders;
}

@dynamic selectedFilePath;
- (NSString *)selectedFilePath {
	return [[self itemAtRow:[self selectedRow]] filePath];
}
#pragma mark *** Private Methods ***
- (IBAction)fileBrowserOutlineViewDoubleAction:(id)sender; {
	id item = [self itemAtRow:[self selectedRow]];
	if ([item isDirectory]) {
		if ([self isItemExpanded:item])
			[self collapseItem:item];
		else
			[self expandItem:item];
	}
}
@end
